<template>
  <div class="my-table-container" v-loading="loading">
    <!-- scrollbar-always-on -->
    <el-table
      ref="tableRef"
      :border="border"
      :size="size"
      highlight-current-row
      :data="tableData"
      :header-cell-style="{ textAlign: cellAlign }"
      :cell-style="{ textAlign: cellAlign }"
      :row-class-name="getRowStyle"
      @cell-dblclick="handleCellDbclick"
      @selection-change="selectionChange"
      :max-height="maxSelfHeight"
      @row-contextmenu="handleContextMenu"
      empty-text="No Data"
      :span-method="arraySpanMethod"
      :summary-method="setSummaries"
      :show-summary="showSummary"
      :row-key="rowKey"
      :scrollbar-always-on="scrollbarShow"
    >
      <!-- :height:"height" -->
      <!-- 多选 start -->
      <el-table-column
        v-if="selection"
        type="selection"
        width="60"
        :fixed="selectionFixed"
        class-name="table-first"
        :selectable="isSelectable"
        :reserve-selection="reserveSelect"
      >
      </el-table-column>
      <template v-for="(item, index) in columns">
        <el-table-column
          v-if="item.multiHeader"
          :fixed="item.fixed"
          :class-name="item.isGray ? 'grayColumn' : ''"
          :show-overflow-tooltip="showOverflowTooltip"
          align="center"
          :label-class-name="labelClassName"
          :label="item.label"
          :sortable="item.sortable"
        >
          <!-- 二级表头 -->
          <el-table-column
            v-for="(item2, index2) in item.children"
            :key="index2"
            :fixed="item2.fixed"
            :class-name="item2.isGray ? 'grayColumn' : ''"
            :prop="item2.prop"
            :show-overflow-tooltip="showOverflowTooltip"
            align="center"
            :min-width="item2.width"
            :label-class-name="labelClassName"
            :label="item2.label"
            :sortable="item2.sortable"
          >
            <!-- 内容处理 start -->
            <template #header="scope">
              <div v-if="item2.slotHeaderName">
                <slot v-bind="scope" :name="item2.slotHeaderName"></slot>
              </div>
              <div v-else>{{ scope.column.label }}</div>
            </template>
            <template #default="scope">
              <span
                v-if="item2.slotName"
                class="table-td cell-content"
                :class="item2.className"
              >
                <slot v-bind="scope" :name="item2.slotName"></slot>
              </span>
              <span v-else class="table-td">
                <template v-if="cellIsEditAble(item2, scope)">
                  <el-date-picker
                    v-if="item2.type == 'DATE'"
                    v-model="scope.row[item2.prop]"
                    type="date"
                    @change="
                      handleBlur(scope.row, scope.column.label, item2.type, item2.prop)
                    "
                    @blur="
                      handleBlur(scope.row, scope.column.label, item2.type, item2.prop)
                    "
                  >
                  </el-date-picker>
                  <el-select
                    v-else-if="item2.type == 'SELECT'"
                    v-model="scope.row[item2.prop]"
                    type="date"
                    @blur="
                      handleBlur(scope.row, scope.column.label, item2.type, item2.prop)
                    "
                    @visible-change="
                      handleVisible(
                        $event,
                        scope.row,
                        scope.column.label,
                        item2.type,
                        item2.prop
                      )
                    "
                  >
                    <el-option
                      v-for="itemOptions in item2.options"
                      :key="itemOptions.value"
                      :label="itemOptions.label"
                      :value="itemOptions.value"
                    />
                  </el-select>
                  <el-input
                    v-else
                    v-model="scope.row[item2.prop]"
                    @input="
                      handleInput(scope.row, scope.column.label, item2.type, item2.prop)
                    "
                    @blur="
                      handleBlur(scope.row, scope.column.label, item2.type, item2.prop)
                    "
                  ></el-input>
                </template>
                <template v-else>
                  <span class="cell-content">
                    {{
                      scope.row[item2.prop] === 0 || !!scope.row[item2.prop]
                        ? scope.row[item2.prop]
                        : ""
                    }}
                  </span>
                </template>
              </span>
            </template>
            <!-- 内容处理  end  -->
          </el-table-column>
        </el-table-column>
        <el-table-column
          v-else
          :fixed="item.fixed"
          :class-name="item.isGray ? 'grayColumn' : ''"
          :prop="item.prop"
          :show-overflow-tooltip="showOverflowTooltip"
          align="center"
          :min-width="item.width"
          :label-class-name="labelClassName"
          :label="item.label"
          :sortable="item.sortable"
        >
          <!-- 内容处理 start -->
          <template #header="scope">
            <div v-if="item.slotHeaderName">
              <slot v-bind="scope" :name="item.slotHeaderName"></slot>
            </div>
            <div v-else>{{ scope.column.label }}</div>
          </template>
          <template #default="scope">
            <span
              v-if="item.slotName"
              class="table-td cell-content"
              :class="item.className"
            >
              <slot v-bind="scope" :name="item.slotName"></slot>
            </span>
            <span v-else class="table-td">
              <template v-if="cellIsEditAble(item, scope)">
                <el-date-picker
                  v-if="item.type == 'DATE'"
                  v-model="scope.row[item.prop]"
                  type="date"
                  @change="
                    handleBlur(scope.row, scope.column.label, item.type, item.prop)
                  "
                  @blur="handleBlur(scope.row, scope.column.label, item.type, item.prop)"
                >
                </el-date-picker>
                <el-select
                  v-else-if="item.type == 'SELECT'"
                  v-model="scope.row[item.prop]"
                  type="date"
                  @blur="handleBlur(scope.row, scope.column.label, item.type, item.prop)"
                  @visible-change="
                    handleVisible(
                      $event,
                      scope.row,
                      scope.column.label,
                      item.type,
                      item.prop
                    )
                  "
                >
                  <el-option
                    v-for="itemOptions in item.options"
                    :key="itemOptions.value"
                    :label="itemOptions.label"
                    :value="itemOptions.value"
                  />
                </el-select>
                <el-input
                  v-else
                  v-model="scope.row[item.prop]"
                  @input="
                    handleInput(scope.row, scope.column.label, item.type, item.prop)
                  "
                  @blur="handleBlur(scope.row, scope.column.label, item.type, item.prop)"
                ></el-input>
              </template>
              <template v-else>
                <span class="cell-content">
                  {{
                    scope.row[item.prop] === 0 || !!scope.row[item.prop]
                      ? scope.row[item.prop]
                      : ""
                  }}
                </span>
              </template>
            </span>
          </template>
          <!-- 内容处理  end  -->
        </el-table-column>
      </template>
    </el-table>
    <!-- 分页处理 start -->
    <template v-if="pagination">
      <div class="page-list">
        <div class="flex-start flex-wrap">
          <div class="page-start flex-center" v-if="selection && showSelectSize">
            <span> 已选 &nbsp;</span>
            <span>{{ selectList }}</span>
          </div>
          <div class="page-container">
            <el-pagination
              :small="true"
              :size="size"
              :page-size="pageSize"
              :current-page="pageIndex"
              :page-sizes="pageSizeList"
              :pager-count="pageCount"
              :layout="paginationLayout"
              :total="totalCount || 0"
              @size-change="paginationOoperate(1, $event)"
              @current-change="paginationOoperate(2, $event)"
            >
            </el-pagination>
          </div>
          <div class="page-end">
            <slot name="end"></slot>
          </div>
        </div>
      </div>
    </template>
    <!-- 分页处理  end  -->
    <div v-if="showContext" class="context-menu" :style="getConetextPosition">
      <template v-for="v in contextMenuList">
        <div
          @click="handleClickContext(v)"
          :style="{ backgroundColor: v.backColor }"
          v-show="
            (!!activeCell.row[activeCell.column.property] && !!v.valueShow) ||
            (!activeCell.row[activeCell.column.property] && !v.valueShow)
          "
        >
          {{ v.label }}
        </div>
      </template>
    </div>
  </div>
</template>

<script>
import {
  defineComponent,
  ref,
  computed,
  watch,
  reactive,
  nextTick,
  onUnmounted,
  onMounted,
  h,
  watchEffect,
} from "vue";
import moment from "moment";
export default defineComponent({
  name: "MyTable",
  components: {},
  props: {
    // 检查表表格表头样式需要单独设计
    isCheckTable: {
      type: Boolean,
      default: false,
    },
    //调整财年计划表格
    isAdjustTable: {
      type: Boolean,
      default: false,
    },
    // 需要设置行字体颜色的index下标
    errorRowList: {
      type: Array,
      default: () => [],
    },
    // 数据总计
    showSummary: {
      type: Boolean,
      default: false,
    },
    summaryList: {
      type: Array,
      default: () => [],
    },
    summarySpan: {
      type: Array,
      default: () => [],
    },
    summaryText: {
      type: String,
      default: "总计",
    },
    border: {
      type: Boolean,
      default: false,
    },
    size: {
      // 頁面路由
      type: String,
      default: "large",
    },
    showOverflowTooltip: {
      type: Boolean,
      default: true,
    },
    jumpColumn: {
      type: Boolean,
      default: false,
    },
    tableData: {
      type: Array,
      default: () => [],
    },
    columns: {
      type: Array,
      default: () => [],
    },
    loading: {
      type: Boolean,
      default: false,
    },
    labelClassName: {
      type: String,
      default: "jumpTable",
    },
    // 分页相关 -- START
    height: {
      type: Number,
      default: 550,
    },
    autoHeight: {
      type: Boolean,
      default: true,
    },
    maxHeight: {
      type: Number,
      default: 550,
    },
    pagination: {
      type: Boolean,
      default: true,
    },
    scrollbarShow: {
      type: Boolean,
      default: true,
    },
    pageSize: {
      type: Number,
      default: 10,
    },
    pageIndex: {
      type: Number,
      default: 1,
    },
    pageSizeList: {
      type: Array,
      default: () => [10, 30, 50, 70, 100],
    },
    pageCount: {
      type: Number,
      default: 7,
    },
    paginationLayout: {
      type: String,
      default: "total, sizes, ->, prev, pager, next, jumper",
    },
    totalCount: {
      type: Number,
      default: null,
    },
    changeSize: {
      type: Function,
      default: () => {},
    },
    changePageIndex: {
      type: Function,
      default: () => {},
    },
    // 分页相关 -- END

    // 多选相关 -- START
    selection: {
      type: Boolean,
      default: false,
    },
    showSelectSize: {
      type: Boolean,
      default: true,
    },
    reserveSelect: {
      type: Boolean,
      default: false,
    },
    rowKey: {
      type: String,
      default: "id",
    },
    notSelectArr: {
      type: Array,
      default: () => [],
    },
    selectionFixed: {
      type: Boolean,
      default: false,
    },
    handleSelectionChange: {
      type: Function,
      default: () => {},
    },

    // 多选相关 -- END

    // 编辑单元格相关 -- START
    changeData: {
      type: Array,
      default: () => [],
    },
    currentEditCells: {
      type: Array,
      default: () => [],
    },
    handleEditDone: {
      type: Function,
      default: () => {},
    },
    handleCellDbclick: {
      type: Function,
      default: () => {},
    },
    // 编辑单元格相关 -- END

    // 右键菜单单元格相关
    contextMenuList: {
      type: Array,
      default: () => [],
    },
    handleClickConextMenu: {
      type: Function,
      default: () => {},
    },
    //合并单元格
    arraySpanMethod: {
      type: Function,
      default: () => {},
    },
    cellAlign: {
      type: String,
      default: "center",
    },
  },
  setup(props, context) {
    let { autoHeight, maxHeight, pagination } = props;
    let maxSelfHeight = ref(maxHeight);
    let stickyClass = ref([]);
    const selectedColumn = ref("");
    const tableRef = ref(null);
    let selectList = ref(0);
    let tableScrollY = ref(null);
    let activeCell = reactive({
      row: "",
      column: "",
    });
    const contextPosition = reactive({ x: 0, y: 0 });
    let showContext = ref(false);
    const handleBlur = (e, label, type, prop) => {
      props.handleEditDone(e, prop);
      // return
      return;
      // 存在select编辑类型需要添加延迟
      // setTimeout(() => {
      //   props.handleEditDone(e, prop);
      //   // return
      //   return;
      // }, 150);
    };
    const handleVisible = (flag, e, label, type, prop) => {
      if (!flag) {
        props.handleEditDone(e, prop);
        // return
        return;
      }
    };
    const handleInput = (e, label, type, prop) => {
      let reg = "";
      switch (type) {
        case "INTEGER":
          reg = /[^0-9-]+/;
          break;
        case "DECIMAL":
          reg = /[^\d\.]/g;
          break;
        default:
          break;
      }
      if (!reg) return;
      let ret = e[prop].replace(reg, "");

      if (ret.split(".").length > 2) {
        e[prop] = ret.slice(0, -1);
        return;
      }
      e[prop] = ret;
    };
    const cellIsEditAble = (item, scope) => {
      let columnEditAble = !!item.editAble;
      let rowEditAble = false;
      props.currentEditCells.forEach((subItem) => {
        if (
          subItem.index == scope.row.index &&
          subItem.property == scope.column.property
        ) {
          rowEditAble = true;
        }
      });
      return columnEditAble && rowEditAble;
    };
    const handleContextMenu = (row, column, e) => {
      let tableColumn = props.columns.filter((item) => item.prop === column["property"]);
      if (tableColumn[0].hasOwnProperty("ctxShow") && tableColumn[0]["ctxShow"]) {
        activeCell.row = row;
        activeCell.column = column;
        let tableCell = e.target;
        if (![...tableCell.classList].includes("el-table__cell")) {
          // 取右键的最大单元格
          tableCell = tableCell.closest(".el-table__cell");
        }
        showContext.value = true;
        let { left: cellLeft, top: cellTop } = tableCell.getBoundingClientRect();
        let { left: tableLeft, top: tableTop } = document
          .querySelector(".my-table-container")
          .getBoundingClientRect();
        e.preventDefault();
        // 计算出右键点击单元格的位置
        //如果最终位置
        contextPosition.x = cellLeft - tableLeft + tableCell.clientWidth / 2;
        contextPosition.y = cellTop - tableTop + tableCell.clientHeight / 2;
      }
    };
    const getConetextPosition = computed(() => {
      let left = contextPosition.x;
      let right = contextPosition.y;
      return {
        left: left + "px",
        top: right + "px",
      };
    });
    const closeMenu = () => {
      showContext.value = false;
    };
    const handleClickContext = (item) => {
      props.handleClickConextMenu(item, activeCell);
    };
    const clearSelection = () => {
      tableRef.value && tableRef.value.clearSelection();
    };
    const toggleRowSelection = (arr, flag = false) => {
      let rowList = props.tableData.filter((v) => arr.includes(v[props.rowKey]));
      rowList.forEach((v) => {
        tableRef.value && tableRef.value.toggleRowSelection(v, flag);
      });
    };
    const getRowStyle = ({ row, rowIndex }) => {
      let str = "";
      if (props.errorRowList.includes(rowIndex)) {
        str += " error-cell";
      }
      return str;
    };
    const handleScroll = () => {
      if (showContext.value) {
        showContext.value = false;
      }
    };
    const isSelectable = (row, index) => {
      if (props.notSelectArr.includes(row[props.rowKey])) {
        return false;
      }
      return true;
    };
    const setSummaries = ({ columns, data }) => {
      let sums = [];
      let columnspan = 1;
      columns.forEach((column, index) => {
        let prop = column.property;
        //数组长度就是对应的需要的总计行数
        let str = "summary-content flex-column-bettween";
        if (props.summarySpan.length > 0) {
          columnspan = props.summarySpan[1];
          if (index === props.summarySpan[0]) {
            str += " summary-columnspan";
          } else if (index < props.summarySpan[1]) {
            str += " summary-hidden";
          }
        }
        let value = props.summaryList.map((v, index) => {
          let content = v[prop] === 0 || !!v[prop] ? v[prop] : "";
          return h("div", { class: "el-table__cell footer-row" }, [
            h("span", { class: "table-td" }, [
              h("span", { class: "cell-content" }, [content]),
            ]),
          ]);
        });
        sums[index] = h("div", { class: str }, [...value]);
      });
      nextTick(() => {
        // 合并单元格
        let columnsRef = document.querySelector(".summary-columnspan");
        let hiddenRef = document.querySelectorAll(".summary-hidden");
        columnsRef &&
          columnsRef.parentElement.parentElement.setAttribute("colspan", columnspan);
        if (hiddenRef) {
          hiddenRef.forEach((v) => {
            v.parentElement.parentElement.style.display = "none";
          });
        }
      });
      return sums;
    };
    const setMaxSelfHeight = () => {
      nextTick(() => {
        let container = document.querySelector(".my-table-container");
        let top = 0;
        let rect = container && container.getBoundingClientRect();
        top = rect ? rect.top : 0;
        let pageHeight = document.body.scrollHeight;
        //底部分页36px
        let paginationHeight = pagination ? 36 : 0;
        // 最终高度还需要减去页面布局上的padding，margin等
        maxSelfHeight.value = pageHeight - paginationHeight - top - 20 - 10 * 2;
      });
    };
    const paginationOoperate = (type, e) => {
      // 改变index和分页大小，回滚到顶部
      tableRef.value && tableRef.value.scrollTo(0, 0);
      if (type === 1) {
        props.changeSize(e);
      } else {
        props.changePageIndex(e);
      }
    };
    const selectionChange = (e) => {
      selectList.value = e.length;
      props.handleSelectionChange(e);
    };
    watch(
      () => showContext.value,
      (value) => {
        if (value) {
          document.body.addEventListener("click", closeMenu);
        } else {
          document.body.removeEventListener("click", closeMenu);
        }
      }
    );
    onMounted(() => {
      nextTick(() => {
        tableScrollY.value = tableRef.value.$el.querySelector(".el-scrollbar__wrap");
        tableScrollY.value.addEventListener("scroll", handleScroll);
      });
      // 将表格最高高度设为占满屏幕
      if (autoHeight) {
        setMaxSelfHeight();
        window.addEventListener("resize", setMaxSelfHeight);
      }
    });
    onUnmounted(() => {
      tableScrollY.value.removeEventListener("scroll", handleScroll);
      if (autoHeight) {
        window.removeEventListener("resize", setMaxSelfHeight);
      }
    });
    return {
      selectList,
      showContext,
      activeCell,
      tableRef,
      selectedColumn,
      cellIsEditAble,
      handleInput,
      handleBlur,
      handleVisible,
      getConetextPosition,
      handleContextMenu,
      contextPosition,
      handleClickContext,
      isSelectable,
      clearSelection,
      getRowStyle,
      toggleRowSelection,
      setSummaries,
      maxSelfHeight,
      paginationOoperate,
      selectionChange,
    };
  },
});
</script>
<style scoped lang="scss">
.my-table-container {
  width: 100%;
  background-color: #fff;
  padding: 0 0 20px;
  border-radius: 16px;
  position: relative;
  overflow: hidden;
}

.page-list {
  overflow: hidden;
  margin-top: 12px;
  padding: 0 15px;
}

.el-table thead th {
  background: #f7f4ef !important;
}

.el-table .cell,
.el-table th div {
  padding-right: 0 !important;
}

.el-table thead th {
  background: #f7f4ef;
}

.el-table--enable-row-hover .el-table__body tr:hover > td {
  background-color: #f7f4ef;
}

.table-first {
  text-align: center !important;
}

.context-menu {
  position: absolute;
  z-index: 100;
  background: transparent;
  display: flex;
  flex-direction: column;
  gap: 10px;
  div {
    padding: 5px 10px;
    border-radius: 10px;
    min-width: 120px;
    text-align: center;
    cursor: pointer;
  }
}

.page-start {
  margin-right: 16px;
  height: 100%;

  span {
    font-size: 12px;
    color: var(--el-text-color-regular);
    font-weight: normal;
  }
}
.page-container {
  flex: 1;
}
.page-end {
  padding-left: 10px;
}
</style>
